/*
 * Wazuh Vulnerability Scanner - Unit Tests
 * Copyright (C) 2015, Wazuh Inc.
 * September 21, 2023.
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License (version 2) as published by the FSF - Free Software
 * Foundation.
 */

#include "eventDecoder_test.hpp"
#include "cve5_generated.h"
#include "databaseFeedManager/eventContext.hpp"
#include "databaseFeedManager/eventDecoder.hpp"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "json.hpp"
#include "rocksDBWrapper.hpp"
#include <memory>
#include <string>
#include <vector>

const std::string CVE_ID {"CVE-2010-0002"};
const std::string TRANSLATION_ID {"TID-0001"};
const std::string VENDOR_MAP_ID {"FEED-GLOBAL"};

auto constexpr CREATED_RESOURCE {R"(
    {
        "offset": 1,
        "type": "create",
        "version": 1,
        "context": "vulnerabilities",
        "resource": "CVE-2010-0002",
        "payload":
        {
            "containers": {
                "adp": [
                    {
                        "metrics": [
                            {
                                "cvssV3_1":
                                {
                                    "scope": "UNCHANGED",
                                    "version": "3.1",
                                    "baseScore": 0.0,
                                    "attackVector": "LOCAL",
                                    "baseSeverity": "NONE",
                                    "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:N",
                                    "integrityImpact": "NONE",
                                    "userInteraction": "NONE",
                                    "attackComplexity": "LOW",
                                    "availabilityImpact": "NONE",
                                    "privilegesRequired": "LOW",
                                    "confidentialityImpact": "NONE",
                                    "environmentalScore": 0,
                                    "temporalScore": 0

                                }
                            }
                        ],
                        "affected": [
                            {
                                "defaultStatus": "unaffected",
                                "platforms": [
                                    "bookworm"
                                ],
                                "product": "bash",
                                "vendor": "debian"
                            },
                            {
                                "defaultStatus": "affected",
                                "platforms": [
                                    "bookworm"
                                ],
                                "product": "bash",
                                "vendor": "debian"
                            }
                        ],
                        "descriptions": [
                            {
                                "lang": "en",
                                "value": "The /etc/profile.d/60alias.sh script in the Mandriva bash package for Bash 2.05b, 3.0, 3.2, 3.2.48, and 4.0 enables the --show-control-chars option in LS_OPTIONS, which allows local users to send escape sequences to terminal emulators, or hide the existence of a file, via a crafted filename."
                            }
                        ],
                        "providerMetadata": {
                            "orgId": "79363d38-fa19-49d1-9214-5f28da3f3ac5"
                        },
                        "references": [
                            {
                                "url": "https://security-tracker.debian.org/tracker/CVE-2010-0002"
                            }
                        ]
                    }
                ],
                "cna": {
                    "affected": [
                        {
                            "cpes": [
                                "cpe:2.3:a:gnu:bash:2.05:b:*:*:*:*:*:*"
                            ],
                            "defaultStatus": "unaffected",
                            "product": "bash b",
                            "vendor": "gnu",
                            "versions": [
                                {
                                    "status": "affected",
                                    "version": "2.05"
                                }
                            ]
                        }
                    ],
                    "descriptions": [
                        {
                            "lang": "en",
                            "value": "The /etc/profile.d/60alias.sh script in the Mandriva bash package for Bash 2.05b, 3.0, 3.2, 3.2.48, and 4.0 enables the --show-control-chars option in LS_OPTIONS, which allows local users to send escape sequences to terminal emulators, or hide the existence of a file, via a crafted filename."
                        }
                    ],
                    "metrics": [
                        {
                            "cvssV2_0": {
                                "accessComplexity": "LOW",
                                "accessVector": "LOCAL",
                                "authentication": "NONE",
                                "availabilityImpact": "PARTIAL",
                                "baseScore": 2.1,
                                "confidentialityImpact": "NONE",
                                "integrityImpact": "NONE",
                                "vectorString": "AV:L/AC:L/Au:N/C:N/I:N/A:P",
                                "version": "2.0",
                                "environmentalScore": 0,
                                "temporalScore": 0

                            },
                            "format": "CVSS"
                        }
                    ],
                    "problemTypes": [
                        {
                            "descriptions": [
                                {
                                    "description": "CWE-20",
                                    "lang": "en"
                                }
                            ]
                        }
                    ],
                    "providerMetadata": {
                        "orgId": "00000000-0000-4000-A000-000000000000",
                        "shortName": "@redhat.com"
                    },
                    "references": [
                        {
                            "name": "https://qa.mandriva.com/show_bug.cgi?id=56882",
                            "url": "https://qa.mandriva.com/show_bug.cgi?id=56882"
                        }
                    ]
                }
            },
            "cveMetadata": {
                "assignerOrgId": "00000000-0000-4000-A000-000000000000",
                "assignerShortName": "@redhat.com",
                "cveId": "CVE-2010-0002",
                "datePublished": "2010-01-14T18:30:00.000Z",
                "dateUpdated": "2011-08-08T04:00:00.000Z",
                "serial": 0,
                "state": "PUBLISHED"
            },
            "dataType": "CVE_RECORD",
            "dataVersion": "5.0"
        }
    }
)"};

auto constexpr UPDATED_RESOURCE {R"(
    {
        "offset": 2,
        "type": "update",
        "version": 1,
        "context": "vulnerabilities",
        "resource": "CVE-2010-0002",
        "operations":
            [
                {
                    "op": "replace",
                    "path": "/containers/adp/0/affected/0/defaultStatus",
                    "value": "unknown"
                },
                {
                    "op": "add",
                    "path": "/containers/adp/0/affected/1/platforms/-",
                    "value": "buster"
                },
                {
                    "op": "remove",
                    "path": "/containers/cna/problemTypes"
                },
                {
                    "op": "replace",
                    "path": "/containers/adp/0/metrics/0/cvssV3_1/baseScore",
                    "value": 7.8
                }
            ]
    }
)"};

auto constexpr UPDATED_DATA {R"(
    {
        "containers": {
            "adp": [
                {
                    "metrics": [
                        {
                            "cvssV3_1":
                            {
                                "scope": "UNCHANGED",
                                "version": "3.1",
                                "baseScore": 7.8,
                                "attackVector": "LOCAL",
                                "baseSeverity": "NONE",
                                "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:N",
                                "integrityImpact": "NONE",
                                "userInteraction": "NONE",
                                "attackComplexity": "LOW",
                                "availabilityImpact": "NONE",
                                "privilegesRequired": "LOW",
                                "confidentialityImpact": "NONE",
                                "environmentalScore": 0,
                                "temporalScore": 0
                            }
                        }
                    ],
                    "affected": [
                        {
                            "defaultStatus": "unknown",
                            "platforms": [
                                "bookworm"
                            ],
                            "product": "bash",
                            "vendor": "debian"
                        },
                        {
                            "defaultStatus": "affected",
                            "platforms": [
                                "bookworm",
                                "buster"
                            ],
                            "product": "bash",
                            "vendor": "debian"
                        }
                    ],
                    "descriptions": [
                        {
                            "lang": "en",
                            "value": "The /etc/profile.d/60alias.sh script in the Mandriva bash package for Bash 2.05b, 3.0, 3.2, 3.2.48, and 4.0 enables the --show-control-chars option in LS_OPTIONS, which allows local users to send escape sequences to terminal emulators, or hide the existence of a file, via a crafted filename."
                        }
                    ],
                    "providerMetadata": {
                        "orgId": "79363d38-fa19-49d1-9214-5f28da3f3ac5"
                    },
                    "references": [
                        {
                            "url": "https://security-tracker.debian.org/tracker/CVE-2010-0002"
                        }
                    ]
                }
            ],
            "cna": {
                "affected": [
                    {
                        "cpes": [
                            "cpe:2.3:a:gnu:bash:2.05:b:*:*:*:*:*:*"
                        ],
                        "defaultStatus": "unaffected",
                        "product": "bash b",
                        "vendor": "gnu",
                        "versions": [
                            {
                                "status": "affected",
                                "version": "2.05"
                            }
                        ]
                    }
                ],
                "descriptions": [
                    {
                        "lang": "en",
                        "value": "The /etc/profile.d/60alias.sh script in the Mandriva bash package for Bash 2.05b, 3.0, 3.2, 3.2.48, and 4.0 enables the --show-control-chars option in LS_OPTIONS, which allows local users to send escape sequences to terminal emulators, or hide the existence of a file, via a crafted filename."
                    }
                ],
                "metrics": [
                    {
                        "cvssV2_0": {
                            "accessComplexity": "LOW",
                            "accessVector": "LOCAL",
                            "authentication": "NONE",
                            "availabilityImpact": "PARTIAL",
                            "baseScore": 2.1,
                            "confidentialityImpact": "NONE",
                            "integrityImpact": "NONE",
                            "vectorString": "AV:L/AC:L/Au:N/C:N/I:N/A:P",
                            "version": "2.0",
                            "environmentalScore": 0,
                            "temporalScore": 0

                        },
                        "format": "CVSS"
                    }
                ],
                "providerMetadata": {
                    "orgId": "00000000-0000-4000-A000-000000000000",
                    "shortName": "@redhat.com"
                },
                "references": [
                    {
                        "name": "https://qa.mandriva.com/show_bug.cgi?id=56882",
                        "url": "https://qa.mandriva.com/show_bug.cgi?id=56882"
                    }
                ]
            }
        },
        "cveMetadata": {
            "assignerOrgId": "00000000-0000-4000-A000-000000000000",
            "assignerShortName": "@redhat.com",
            "cveId": "CVE-2010-0002",
            "datePublished": "2010-01-14T18:30:00.000Z",
            "dateUpdated": "2011-08-08T04:00:00.000Z",
            "serial": 0,
            "state": "PUBLISHED"
        },
        "dataType": "CVE_RECORD",
        "dataVersion": "5.0"
    }
)"};

auto constexpr DELETED_RESOURCE {R"(
    {
        "offset": 3,
        "type": "delete",
        "version": 1,
        "context": "vulnerabilities",
        "resource": "CVE-2010-0002"
    }
)"};

auto constexpr INVALID_TYPE {R"(
    {
        "offset": 3,
        "type": "invalid",
        "version": 1,
        "context": "vulnerabilities",
        "resource": "CVE-2010-0002"
    }
)"};

auto constexpr CREATE_TRANSLATION {
    R"(
            {
                "offset": 5,
                "type": "create",
                "version": 1,
                "context": "translation",
                "resource": "TID-0001",
                "payload": {
                    "target": "windows",
                    "source": {
                        "vendor": "Microsoft Corporation",
                        "product": "Microsoft Edge",
                        "version": ""
                    },
                    "translation": [
                        {
                        "vendor": "microsoft",
                        "product": "edge_chromium",
                        "version": ""
                        }
                    ],
                    "action": [
                        "replace_vendor",
                        "replace_product"
                    ]
                }
            }
    )"};

auto constexpr UPDATE_TRANSLATION {
    R"(
            {
                "offset": 2,
                "type": "update",
                "version": 1,
                "context": "vulnerabilities",
                "resource": "TID-0001",
                "operations": [
                    {
                        "op": "replace",
                        "path": "/translation/0/vendor",
                        "value": "microsoft corporation"
                    },
                    {
                        "op": "add",
                        "path": "/translation/1",
                        "value": {
                        "vendor": "microsoft",
                        "product": "edge_chromium",
                        "version": ""
                        }
                    },
                    {
                        "op": "replace",
                        "path": "/source/product",
                        "value": "Microsoft Edge Browser"
                    },
                    {
                        "op": "replace",
                        "path": "/source/vendor",
                        "value": "Microsoft"
                    }
                ]
            }
    )"};

auto constexpr UPDATED_TRANSLATION_DATA {
    R"(
            {
                "target": "windows",
                "source": {
                    "vendor": "Microsoft",
                    "product": "Microsoft Edge Browser",
                    "version": ""
                },
                "translation": [
                    {
                        "vendor": "microsoft corporation",
                        "product": "edge_chromium",
                        "version": ""
                    },
                    {
                        "vendor": "microsoft",
                        "product": "edge_chromium",
                        "version": ""
                    }
                ],
                "action": [
                    "replace_vendor",
                    "replace_product"
                ]
            }
    )"};

auto constexpr DELETE_TRANSLATION {
    R"(
        {
            "offset": 2,
            "type": "delete",
            "version": 1,
            "context": "vulnerabilities",
            "resource": "TID-0001"
        }
    )"};

auto constexpr VENDOR_MAP {R"(
    {
        "offset": 1,
        "type": "create",
        "version": 1,
        "context": "vulnerabilities",
        "resource": "FEED-GLOBAL",
        "payload": {
            "prefix": [
                {"Canonical": "canonical"},
                {"Ubuntu": "canonical"},
                {"Debian": "debian"},
                {"Red Hat, Inc.": "redhat"},
                {"CentOS": "redhat"},
                {"Amazon Linux": "alas"},
                {"Amazon.com": "alas"},
                {"Amazon AWS": "alas"},
                {"Arch Linux": "arch"},
                {"suse": "suse"},
                {"AlmaLinux": "almalinux"},
                {"CloudLinux": "almalinux"}
            ],
            "contains": [
                {"@ubuntu.com": "canonical"}
            ],
            "format": [
                {"pypi": "pypi"},
                {"npm": "npm"}
            ]
        }
    }
    )"};

auto constexpr UPDATE_VENDOR_MAP {
    R"(
        {
            "offset": 2,
            "type": "update",
            "version": 1,
            "context": "vulnerabilities",
            "resource": "FEED-GLOBAL",
            "operations": [
                {
                    "op": "add",
                    "path": "/prefix/-",
                    "value": {
                        "New Vendor": "new_vendor"
                    }
                },
                {
                    "op": "replace",
                    "path": "/contains/0",
                    "value": {
                        "New Vendor Replaced": "new_vendor_replaced"
                    }
                }
            ]
        }
    )"};

/*
 * @brief Test a new resource.
 */
TEST_F(EventDecoderTest, TestCreatedResource)
{
    std::vector<char> message {};
    auto jsonResource = nlohmann::json::parse(CREATED_RESOURCE);
    auto eventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = jsonResource, .feedDatabase = m_feedDb.get()});

    std::shared_ptr<EventDecoder> eventDecoder;

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // HandleRequest
    EXPECT_NO_THROW(eventDecoder->handleRequest(eventContext));

    // Verify flatbuffer.
    rocksdb::PinnableSlice slice;
    EXPECT_TRUE(m_feedDb->get(CVE_ID, slice, COLUMNS.at(ResourceType::CVE)));

    flatbuffers::Verifier verifierCVE5(reinterpret_cast<const uint8_t*>(slice.data()), slice.size());
    EXPECT_TRUE(cve_v5::VerifyEntryBuffer(verifierCVE5));

    // Verify data
    flatbuffers::IDLOptions options;
    options.output_default_scalars_in_json = true;
    options.strict_json = true;

    flatbuffers::Parser parser(options);
    EXPECT_TRUE(parser.Parse(cve5_SCHEMA));

    std::string jsongen;
    flatbuffers::GenText(parser, reinterpret_cast<const uint8_t*>(slice.data()), &jsongen);
    EXPECT_EQ(nlohmann::json::parse(jsongen), jsonResource.at("payload"));
}

/*
 * @brief Test a new translation resource.
 */
TEST_F(EventDecoderTest, TestCreatedTranslationResource)
{
    std::vector<char> message {};
    auto jsonResource = nlohmann::json::parse(CREATE_TRANSLATION);
    auto eventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = jsonResource, .feedDatabase = m_feedDb.get()});

    std::shared_ptr<EventDecoder> eventDecoder;

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // HandleRequest
    EXPECT_NO_THROW(eventDecoder->handleRequest(eventContext));

    // Verify flatbuffer.
    rocksdb::PinnableSlice slice;
    EXPECT_TRUE(m_feedDb->get(TRANSLATION_ID, slice, COLUMNS.at(ResourceType::TRANSLATION)));

    flatbuffers::Verifier verifierTranslation(reinterpret_cast<const uint8_t*>(slice.data()), slice.size());
    EXPECT_TRUE(NSVulnerabilityScanner::VerifyTranslationEntryBuffer(verifierTranslation));

    // Verify data
    flatbuffers::IDLOptions options;
    options.strict_json = true;

    flatbuffers::Parser parser(options);
    EXPECT_TRUE(parser.Parse(packageTranslation_SCHEMA));

    std::string jsongen;
    flatbuffers::GenText(parser, reinterpret_cast<const uint8_t*>(slice.data()), &jsongen);
    EXPECT_EQ(nlohmann::json::parse(jsongen), jsonResource.at("payload"));
}

/*
 * @brief Test an update for a resource.
 */
TEST_F(EventDecoderTest, TestUpdatedResource)
{
    std::vector<char> message {};
    auto jsonResource = nlohmann::json::parse(CREATED_RESOURCE);
    auto eventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = jsonResource, .feedDatabase = m_feedDb.get()});

    std::shared_ptr<EventDecoder> eventDecoder;

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // HandleRequest
    EXPECT_NO_THROW(eventDecoder->handleRequest(eventContext));

    // Apply update
    auto updatedJsonResource = nlohmann::json::parse(UPDATED_RESOURCE);
    auto updatedEventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = updatedJsonResource, .feedDatabase = m_feedDb.get()});
    EXPECT_NO_THROW(eventDecoder->handleRequest(updatedEventContext));

    // Verify flatbuffer.
    rocksdb::PinnableSlice slice;
    EXPECT_TRUE(m_feedDb->get(CVE_ID, slice, COLUMNS.at(ResourceType::CVE)));

    flatbuffers::Verifier verifierCVE5(reinterpret_cast<const uint8_t*>(slice.data()), slice.size());
    EXPECT_TRUE(cve_v5::VerifyEntryBuffer(verifierCVE5));

    // Verify data
    flatbuffers::IDLOptions options;
    options.output_default_scalars_in_json = true;
    options.strict_json = true;

    flatbuffers::Parser parser(options);
    EXPECT_TRUE(parser.Parse(cve5_SCHEMA));

    std::string jsongen;
    flatbuffers::GenText(parser, reinterpret_cast<const uint8_t*>(slice.data()), &jsongen);
    EXPECT_EQ(nlohmann::json::parse(jsongen), nlohmann::json::parse(UPDATED_DATA));
}

/*
 * @brief Test an update for a resource with corrupted data in rocksdb.
 */
TEST_F(EventDecoderTest, TestUpdatedResourceCorrupted)
{
    std::vector<char> message {};

    // Simulate corrupted data stored
    {
        uint8_t corruptedData[] = {
            0x55, 0xCC, 0x00, 0xFF, 0x55, 0xCC, 0x00, 0xFF, 0x55, 0xCC, 0x00, 0xFF, 0x55, 0xCC, 0x00, 0xFF};
        rocksdb::Slice dbValue(reinterpret_cast<const char*>(corruptedData), sizeof(corruptedData));
        m_feedDb->put("CVE-2010-0002", dbValue, COLUMNS.at(ResourceType::CVE));
    }

    std::shared_ptr<EventDecoder> eventDecoder;

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // Apply update
    auto updatedJsonResource = nlohmann::json::parse(UPDATED_RESOURCE);
    auto updatedEventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = updatedJsonResource, .feedDatabase = m_feedDb.get()});

    EXPECT_THROW(eventDecoder->handleRequest(updatedEventContext), std::runtime_error);
}

/*
 * @brief Test an update for a translation resource.
 */
TEST_F(EventDecoderTest, TestUpdatedTranslationResource)
{
    std::vector<char> message {};
    auto jsonResource = nlohmann::json::parse(CREATE_TRANSLATION);
    auto eventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = jsonResource, .feedDatabase = m_feedDb.get()});

    std::shared_ptr<EventDecoder> eventDecoder;

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // HandleRequest
    EXPECT_NO_THROW(eventDecoder->handleRequest(eventContext));

    // Apply update
    auto updatedJsonResource = nlohmann::json::parse(UPDATE_TRANSLATION);
    auto updatedEventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = updatedJsonResource, .feedDatabase = m_feedDb.get()});
    EXPECT_NO_THROW(eventDecoder->handleRequest(updatedEventContext));

    // Verify flatbuffer.
    rocksdb::PinnableSlice slice;
    EXPECT_TRUE(m_feedDb->get(TRANSLATION_ID, slice, COLUMNS.at(ResourceType::TRANSLATION)));

    flatbuffers::Verifier verifierTranslation(reinterpret_cast<const uint8_t*>(slice.data()), slice.size());
    EXPECT_TRUE(NSVulnerabilityScanner::VerifyTranslationEntryBuffer(verifierTranslation));

    // Verify data
    flatbuffers::IDLOptions options;
    options.strict_json = true;

    flatbuffers::Parser parser(options);
    EXPECT_TRUE(parser.Parse(packageTranslation_SCHEMA));

    std::string jsongen;
    flatbuffers::GenText(parser, reinterpret_cast<const uint8_t*>(slice.data()), &jsongen);
    EXPECT_EQ(nlohmann::json::parse(jsongen), nlohmann::json::parse(UPDATED_TRANSLATION_DATA));
}

/*
 * @brief Test an update for a translation resource with corrupted data in rocksdb.
 */
TEST_F(EventDecoderTest, TestUpdatedTranslationResourceCorrupted)
{
    std::vector<char> message {};

    // Simulate corrupted data stored
    {
        uint8_t corruptedData[] = {
            0x55, 0xCC, 0x00, 0xFF, 0x55, 0xCC, 0x00, 0xFF, 0x55, 0xCC, 0x00, 0xFF, 0x55, 0xCC, 0x00, 0xFF};
        rocksdb::Slice dbValue(reinterpret_cast<const char*>(corruptedData), sizeof(corruptedData));
        m_feedDb->put("TID-0001", dbValue, COLUMNS.at(ResourceType::TRANSLATION));
    }

    std::shared_ptr<EventDecoder> eventDecoder;

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // Apply update
    auto updatedJsonResource = nlohmann::json::parse(UPDATE_TRANSLATION);
    auto updatedEventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = updatedJsonResource, .feedDatabase = m_feedDb.get()});

    EXPECT_THROW(eventDecoder->handleRequest(updatedEventContext), std::runtime_error);
}

/*
 * @brief Test the deletion of a translation resource.
 */
TEST_F(EventDecoderTest, TestDeletedTranslationResource)
{
    std::vector<char> message {};
    auto jsonResource = nlohmann::json::parse(CREATE_TRANSLATION);
    auto eventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = jsonResource, .feedDatabase = m_feedDb.get()});

    std::shared_ptr<EventDecoder> eventDecoder;

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // HandleRequest
    EXPECT_NO_THROW(eventDecoder->handleRequest(eventContext));

    // Apply update
    auto deletedJsonResource = nlohmann::json::parse(DELETE_TRANSLATION);
    auto deletedEventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = deletedJsonResource, .feedDatabase = m_feedDb.get()});
    EXPECT_NO_THROW(eventDecoder->handleRequest(deletedEventContext));

    // Verify flatbuffer.
    rocksdb::PinnableSlice slice;
    EXPECT_FALSE(m_feedDb->get(TRANSLATION_ID, slice, COLUMNS.at(ResourceType::TRANSLATION)));
}

/*
 * @brief Test an invalid operation.
 */
TEST_F(EventDecoderTest, TestInvalidOperation)
{
    std::vector<char> message {};
    auto jsonResource = nlohmann::json::parse(INVALID_TYPE);
    auto eventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = jsonResource, .feedDatabase = m_feedDb.get()});

    std::shared_ptr<EventDecoder> eventDecoder;

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // HandleRequest
    EXPECT_THROW(eventDecoder->handleRequest(eventContext), std::runtime_error);
}

/*
 * @brief Test a new vendor map resource.
 */
TEST_F(EventDecoderTest, TestCreatedVendorMap)
{
    std::vector<char> message {};
    auto jsonResource = nlohmann::json::parse(VENDOR_MAP);
    auto eventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = jsonResource, .feedDatabase = m_feedDb.get()});

    std::shared_ptr<EventDecoder> eventDecoder;

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // HandleRequest
    EXPECT_NO_THROW(eventDecoder->handleRequest(eventContext));

    // Verify data
    rocksdb::PinnableSlice slice;
    EXPECT_TRUE(m_feedDb->get(VENDOR_MAP_ID, slice, COLUMNS.at(ResourceType::VENDOR_MAP)));
    auto result = nlohmann::json::parse(slice.ToString());

    EXPECT_EQ(nlohmann::json::parse(VENDOR_MAP).at("payload"), result);
}

/*
 * @brief Test a vendor map update
 */
TEST_F(EventDecoderTest, TestUpdatedVendorMap)
{
    std::vector<char> message {};
    auto jsonResource = nlohmann::json::parse(VENDOR_MAP);
    auto eventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = jsonResource, .feedDatabase = m_feedDb.get()});

    std::shared_ptr<EventDecoder> eventDecoder;
    auto updatedJsonResource = nlohmann::json::parse(UPDATE_VENDOR_MAP);
    auto updatedEventContext = std::make_shared<EventContext>(
        EventContext {.message = message, .resource = updatedJsonResource, .feedDatabase = m_feedDb.get()});

    // Instantiation of the EventDecoder class.
    EXPECT_NO_THROW(eventDecoder = std::make_shared<EventDecoder>());

    // HandleRequest
    EXPECT_NO_THROW(eventDecoder->handleRequest(eventContext));
    EXPECT_NO_THROW(eventDecoder->handleRequest(updatedEventContext));

    // Verify data
    rocksdb::PinnableSlice slice;
    EXPECT_TRUE(m_feedDb->get(VENDOR_MAP_ID, slice, COLUMNS.at(ResourceType::VENDOR_MAP)));
    auto result = nlohmann::json::parse(slice.ToString());

    {
        bool found = false;
        for (const auto& item : result.at("prefix"))
        {
            if (item.begin().key() == "New Vendor")
            {
                EXPECT_EQ(item.begin().value(), "new_vendor");
                found = true;
                break;
            }
        }
        EXPECT_TRUE(found);
    }
    EXPECT_EQ(result.at("/contains/0/New Vendor Replaced"_json_pointer), "new_vendor_replaced");
}
